#!/usr/bin/env python3
"""
Docker端口配置修复工具
==================

基于端口审计结果修复Docker配置中的端口不一致问题
- 修复Dockerfile中的EXPOSE端口
- 修复docker-compose.yml中的端口映射和健康检查
- 确保所有端口配置一致

执行: python tools/fix_docker_ports.py
"""

import os
import re
import yaml
from pathlib import Path
from typing import Dict, List, Tuple

class DockerPortFixer:
    """Docker端口配置修复器"""
    
    def __init__(self, backend_path: str = "backend"):
        self.backend_path = Path(backend_path)
        self.apps_path = self.backend_path / "apps"
        self.deploy_path = self.backend_path / "deploy"
        
        # 标准端口分配（基于审计发现的正确配置）
        self.standard_ports = {
            "api-gateway": 8000,
            "user_service": 8001,
            "auth-service": 8002,
            "trading-service": 8003,
            "strategy-service": 8004,
            "market-data-service": 8005,
            "notification-service": 8006,
            "monitoring-service": 8007
        }
        
        # 当前Dockerfile中错误的端口配置
        self.dockerfile_port_errors = {
            "auth-service": {"current": 8005, "correct": 8002},
            "market-data-service": {"current": 8003, "correct": 8005},
            "monitoring-service": {"current": 8006, "correct": 8007},
            "notification-service": {"current": 8007, "correct": 8006},
            "trading-service": {"current": 8002, "correct": 8003}
        }
    
    def fix_all_services(self):
        """修复所有服务的端口配置"""
        print("🔧 开始修复Docker端口配置...")
        
        # 修复Dockerfile端口
        self._fix_dockerfile_ports()
        
        # 验证docker-compose.yml配置正确性
        self._verify_compose_config()
        
        print("✅ 端口配置修复完成!")
    
    def _fix_dockerfile_ports(self):
        """修复Dockerfile中的EXPOSE端口"""
        print("\n📝 修复Dockerfile端口...")
        
        for service_name, port_info in self.dockerfile_port_errors.items():
            dockerfile_path = self.apps_path / service_name / "Dockerfile"
            
            if not dockerfile_path.exists():
                print(f"⚠️  Dockerfile不存在: {dockerfile_path}")
                continue
            
            try:
                # 读取文件内容
                content = dockerfile_path.read_text(encoding='utf-8')
                
                # 替换EXPOSE端口
                old_expose = f"EXPOSE {port_info['current']}"
                new_expose = f"EXPOSE {port_info['correct']}"
                
                if old_expose in content:
                    new_content = content.replace(old_expose, new_expose)
                    
                    # 写回文件
                    dockerfile_path.write_text(new_content, encoding='utf-8')
                    print(f"  ✅ {service_name}: {port_info['current']} → {port_info['correct']}")
                else:
                    print(f"  ⚠️  {service_name}: 未找到 EXPOSE {port_info['current']}")
                    
            except Exception as e:
                print(f"  ❌ {service_name}: 修复失败 - {e}")
    
    def _verify_compose_config(self):
        """验证docker-compose.yml配置的正确性"""
        print("\n🔍 验证docker-compose.yml配置...")
        
        compose_path = self.deploy_path / "docker-compose.yml"
        if not compose_path.exists():
            print(f"❌ docker-compose.yml不存在: {compose_path}")
            return
        
        try:
            with open(compose_path, 'r', encoding='utf-8') as f:
                compose_data = yaml.safe_load(f)
            
            services = compose_data.get('services', {})
            issues_found = False
            
            for service_name, standard_port in self.standard_ports.items():
                if service_name not in services:
                    continue
                
                service_config = services[service_name]
                
                # 检查端口映射
                ports = service_config.get('ports', [])
                if ports:
                    port_mapping = ports[0]
                    if ':' in port_mapping:
                        external, internal = port_mapping.split(':')
                        external_port = int(external)
                        internal_port = int(internal)
                        
                        if external_port != standard_port or internal_port != standard_port:
                            print(f"  ⚠️  {service_name}: 端口映射 {port_mapping}, 应为 {standard_port}:{standard_port}")
                            issues_found = True
                        else:
                            print(f"  ✅ {service_name}: 端口映射正确 ({standard_port}:{standard_port})")
                
                # 检查健康检查
                healthcheck = service_config.get('healthcheck', {})
                if healthcheck:
                    test_cmd = healthcheck.get('test', [])
                    if test_cmd:
                        health_cmd = ' '.join(test_cmd)
                        port_pattern = r'localhost:(\d+)'
                        port_match = re.search(port_pattern, health_cmd)
                        if port_match:
                            health_port = int(port_match.group(1))
                            if health_port != standard_port:
                                print(f"  ⚠️  {service_name}: 健康检查端口 {health_port}, 应为 {standard_port}")
                                issues_found = True
                            else:
                                print(f"  ✅ {service_name}: 健康检查端口正确 ({standard_port})")
            
            if not issues_found:
                print("  🎉 docker-compose.yml配置全部正确!")
            else:
                print("  💡 如发现问题，请手动修复docker-compose.yml")
                
        except Exception as e:
            print(f"❌ 验证失败: {e}")
    
    def generate_port_summary(self):
        """生成端口配置总结"""
        print(f"\n📊 标准端口分配总结:")
        print(f"{'服务名称':<20} {'端口':<6} {'状态'}")
        print("-" * 35)
        
        for service_name, port in self.standard_ports.items():
            status = "修复" if service_name in self.dockerfile_port_errors else "正确"
            print(f"{service_name:<20} {port:<6} {status}")


def main():
    """主函数"""
    print("🚀 RedFire Docker端口配置修复工具")
    print("=" * 50)
    
    # 检查工作目录
    if not Path("backend").exists():
        print("❌ 错误: 请在项目根目录运行此脚本")
        return
    
    try:
        # 创建修复器
        fixer = DockerPortFixer()
        
        # 显示当前问题
        print("🔍 检测到的端口配置问题:")
        for service, info in fixer.dockerfile_port_errors.items():
            print(f"  - {service}: Dockerfile EXPOSE {info['current']} → 应为 {info['correct']}")
        
        # 询问用户确认
        response = input(f"\n是否继续修复这些问题? (y/N): ").lower().strip()
        if response not in ['y', 'yes']:
            print("❌ 用户取消修复")
            return
        
        # 执行修复
        fixer.fix_all_services()
        
        # 生成总结
        fixer.generate_port_summary()
        
        print(f"\n💡 下一步建议:")
        print(f"  1. 运行端口审计验证修复: python tools/docker_port_audit.py")
        print(f"  2. 重新构建Docker镜像")
        print(f"  3. 测试服务启动")
        
    except Exception as e:
        print(f"❌ 修复失败: {e}")
        raise


if __name__ == "__main__":
    main()
